package vista;

import java.awt.Dimension;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;

import constants.Constants;
import controller.Controller;
import controller.NetworkHandler;
import controller.NetworkListener;
import controller.ServerMessage;

public class MainGUI extends JFrame implements Runnable, NetworkListener, ActionListener, MouseListener{


	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	private static final int DISPLAY_WIDTH = 1000; 
	private static final int DISPLAY_HEIGHT = 600;
	private final int DISPLAY_X;
	private final int DISPLAY_Y;
	private BufferedImage boardImage,imagenMarcado,menuTitle, suspectSheet,fondoRightMenuPanel,buttonsRightMenu;
	private Icon buttonsRightMenuPanel;
	
	private List<Image> monkImages = new ArrayList<Image>();
	private List<Image> playerImages = new ArrayList<Image>();
	private List<Image> cardImages = new ArrayList<Image>();
	private List<Image> misaImages = new ArrayList<Image>();
	private List<Image> dicesImages = new ArrayList<Image>();
	
	private ImageIcon inputFrameImage;
	private ImageIcon revelationFrameImage;
	private ImageIcon meetingFrameImage;
	private ImageIcon buttonImageIcon;
	private ImageIcon buttonRevelationImageIcon;
	
	
	private Queue<ServerMessage> messageList;
	private boolean running = true;
	private BoardArea board;
	private RightMenuPanel rightMenu;
	private Controller gameController;
	
	private InputFrame inputFrame;
	private CardsPanel cardsPanel;
	private SuspectsPanel suspectsPanel;
	private MeetingPanel meetingPanel;
	private revelationPanel revelationPanel;
	private ImageMessage imageMessage;
	private PlayCardFrame playCardPanel;
	
	private static MainGUI instance = null;
	private static byte gameState = 0;
	private int playerId;
	private String playerName;

	

	public MainGUI(Controller gamecontroller) {
		instance = this;
		this.gameController = gamecontroller;
		//this.setAlwaysOnTop(true);

		loadImages();
		
		messageList = new LinkedList<ServerMessage>();
		
		Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
		System.out.println(d.height);
		System.out.println(d.width);
		
		this.setLocation(new Point((d.width-DISPLAY_WIDTH)/2,(d.height-DISPLAY_HEIGHT)/2));
		this.setVisible(true);
		
		Insets insets = this.getInsets();
		DISPLAY_X = insets.left; 
		DISPLAY_Y = insets.top;
		
		this.setLayout(null);
		this.setIgnoreRepaint(true);
		this.setResizable(false);
		
		DisplayArea display = new DisplayArea(new Rectangle(DISPLAY_X, DISPLAY_Y, DISPLAY_WIDTH, DISPLAY_HEIGHT));
		board = new BoardArea(new Rectangle(0, 0, display.getWidth() * 3/4, display.getHeight()),boardImage,playerImages,gameController);
		rightMenu = new RightMenuPanel(new Rectangle(display.getWidth() * 3/4, 0, display.getWidth() - display.getWidth() * 3/4, display.getHeight()),menuTitle,buttonsRightMenuPanel,fondoRightMenuPanel,cardImages.get(1));
		
		cardsPanel = new CardsPanel(monkImages,new Rectangle(getLocation().x +10 ,getLocation().y +15,600,600));
		suspectsPanel= new SuspectsPanel(suspectSheet,imagenMarcado);
		inputFrame = new InputFrame(new Rectangle(getLocation().x + DISPLAY_WIDTH/2 -200,getLocation().y + DISPLAY_HEIGHT/2 -100,300,200),inputFrameImage,buttonImageIcon);
		imageMessage = new ImageMessage(new Rectangle(getLocation().x + DISPLAY_WIDTH/2 -150,getLocation().y + DISPLAY_HEIGHT/2 -200,250,400), cardImages, monkImages,misaImages);
		
		display.add(board);
		display.add(rightMenu);
		
		this.setDefaultCloseOperation(EXIT_ON_CLOSE);
		this.setContentPane(display);
		
		Thread mainloop = new Thread(this);
		mainloop.start();
		
		resizeToInternalSize(DISPLAY_WIDTH,DISPLAY_HEIGHT);
		
	}
	
	public static MainGUI getInstance() {
		return instance;
	}
	
	public static byte getGameState(){
		return gameState;
	}
	
	
	public void resizeToInternalSize(int internalWidth, int internalHeight){
		Insets insets = this.getInsets();
		final int newWidth = internalWidth + insets.left + insets.right;
		final int newHeight = internalHeight + insets.top + insets.bottom;
		setSize(newWidth, newHeight);
	}
	
	
	@Override
	public void run() {
		
		long elapsedTime,startTime,waitTime;
		int delayTime = 1000 / 40;
		while(running) {
			
			startTime = System.currentTimeMillis();
			
			handleNetworkMessages();
			repaint();
			
			elapsedTime = System.currentTimeMillis() - startTime;
			waitTime = Math.max(delayTime - elapsedTime, 5);
			
			try {
				Thread.sleep(waitTime);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}	
		}
	}
	
	public void kill() {
		running = false;
	}


	private void loadImages() {
		
		try {
			boardImage = ImageIO.read(new File("img/AbadiaFond.jpg"));
			imagenMarcado = ImageIO.read(new File("img/botones de marcado.png"));
			suspectSheet = ImageIO.read(new File("img/sospechosos.jpg"));
			fondoRightMenuPanel = ImageIO.read(new File("img/fondoRightMenuPanel.jpg"));
			buttonsRightMenu =ImageIO.read(new File("img/botonesRighMenuPanel.png"));
			buttonsRightMenuPanel=new ImageIcon(buttonsRightMenu);
			
			inputFrameImage = new ImageIcon("img/panelPrincipal.png");
			buttonImageIcon = new ImageIcon("img/botonesRighMenuPanel.png");
			revelationFrameImage = new ImageIcon("img/SALACAPITULAR.png");
			buttonRevelationImageIcon = new ImageIcon("img/botonRevelacion.png");
			meetingFrameImage = new ImageIcon("img/encuentro.png");
			
			Image player;
			Image scaledPlayer;
			
			player = ImageIO.read(new File("img/playerImg/playerRed.png"));
			scaledPlayer = player.getScaledInstance(40, 80, BufferedImage.SCALE_SMOOTH);
			playerImages.add(scaledPlayer);
			
			player = ImageIO.read(new File("img/playerImg/playerBlack.png"));
			scaledPlayer = player.getScaledInstance(40, 80, BufferedImage.SCALE_SMOOTH);
			playerImages.add(scaledPlayer);
			
			player = ImageIO.read(new File("img/playerImg/playerGreen.png"));
			scaledPlayer = player.getScaledInstance(40, 80, BufferedImage.SCALE_SMOOTH);
			playerImages.add(scaledPlayer);
			
			player = ImageIO.read(new File("img/playerImg/playerBlue.png"));
			scaledPlayer = player.getScaledInstance(40, 80, BufferedImage.SCALE_SMOOTH);
			playerImages.add(scaledPlayer);
			
			player = ImageIO.read(new File("img/playerImg/playerYellow.png"));
			scaledPlayer = player.getScaledInstance(40, 80, BufferedImage.SCALE_SMOOTH);
			playerImages.add(scaledPlayer);
			
			player = ImageIO.read(new File("img/playerImg/playerWhite.png"));
			scaledPlayer = player.getScaledInstance(40, 80, BufferedImage.SCALE_SMOOTH);
			playerImages.add(scaledPlayer);
			
			
		} catch (IOException e) {

			e.printStackTrace();
		}
			
		String[] monkNameList = {"Mattew","William","Fortune","Harold","Malachi","Gerard","Basil","Thomas","Galbraith","Michael","Emmanuel","Cuthbert","Jacques","Bartholomew","Andre","Nicholas","Bruno","Sergio","Berengar","Julian","Cyrille","Charles","Philippe","Guy"};
		for(int i=0; i<monkNameList.length;i++)
			try {
				menuTitle=ImageIO.read(new File("img/Menutitle.png"));
				Image monk = ImageIO.read(new File("img/monjes/"+monkNameList[i]+".png"));
				//Image scaledMonk = monk.getScaledInstance(87, 160, BufferedImage.SCALE_SMOOTH);
				monkImages.add(monk);
				
			} catch (IOException e) {
				System.out.println(e);
				System.out.println("NO se pudo cargar la imagen"+monkNameList[i]+".png");
			}
		
		//CARDIMAGES
		try {
			Image cardImage1 = ImageIO.read(new File("img/cardImages/biblioteca.png"));
			Image cardImage2 = ImageIO.read(new File("img/cardImages/cripta.png"));
			Image cardImage3 = ImageIO.read(new File("img/cardImages/evento.png"));
			Image cardImage4 = ImageIO.read(new File("img/cardImages/scriptoriumDado.png"));
			Image cardImage5 = ImageIO.read(new File("img/cardImages/scriptoriumEspecial.png"));
			Image cardImage6 = ImageIO.read(new File("img/cardImages/scriptoriumNormal.png"));
			cardImages.add(cardImage1);
			cardImages.add(cardImage2);
			cardImages.add(cardImage3);
			cardImages.add(cardImage4);
			cardImages.add(cardImage5);
			cardImages.add(cardImage6);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		//MISACARDIMAGES
		try {
			Image misaImage1 = ImageIO.read(new File("img/MisasCards/MAITINES.png"));
			Image misaImage2 = ImageIO.read(new File("img/MisasCards/LAUDES.png"));
			Image misaImage3 = ImageIO.read(new File("img/MisasCards/PRIMA.png"));
			Image misaImage4 = ImageIO.read(new File("img/MisasCards/TERCIA.png"));
			Image misaImage5 = ImageIO.read(new File("img/MisasCards/SEXTA.png"));
			Image misaImage6 = ImageIO.read(new File("img/MisasCards/NONA.png"));
			Image misaImage7 = ImageIO.read(new File("img/MisasCards/VISPERAS.png"));
			Image misaImage8 = ImageIO.read(new File("img/MisasCards/COMPLETAS.png"));
			
			misaImages.add(misaImage1);
			misaImages.add(misaImage2);
			misaImages.add(misaImage3);
			misaImages.add(misaImage4);
			misaImages.add(misaImage5);
			misaImages.add(misaImage6);
			misaImages.add(misaImage7);
			misaImages.add(misaImage8);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		try {
			Image diceImage1 = ImageIO.read(new File("img/dados/dadoAmarillo.png"));
			Image diceImage2 = ImageIO.read(new File("img/dados/dadoAzul.png"));
			Image diceImage3 = ImageIO.read(new File("img/dados/dadoBlanco.png"));
			Image diceImage4 = ImageIO.read(new File("img/dados/dadoNegro.png"));
			Image diceImage5 = ImageIO.read(new File("img/dados/dadoRojo.png"));
			Image diceImage6 = ImageIO.read(new File("img/dados/dadoVerde.png"));
			
			
			dicesImages.add(diceImage1);
			dicesImages.add(diceImage2);
			dicesImages.add(diceImage3);
			dicesImages.add(diceImage4);
			dicesImages.add(diceImage5);
			dicesImages.add(diceImage6);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	
		//MISACARDIMAGES
	}
	
	
	private void handleNetworkMessages() {
		ServerMessage message;
		
		while(messageList.size()>0) {
			
			synchronized(messageList) 
			{
				message = messageList.poll();
			}
			
			if(message != null) 
			{
				List<String> infoList = message.getInfoList();
				
				switch(message.getCommand()) 
				{
				
				case END:
					GameLogic.gameState = Constants.GAME_FINISHED;
					rightMenu.updateState();
					break;

				case GAME_STARTED:
					playerId = Integer.parseInt(infoList.get(0));
					playerName = infoList.get(1);
					rightMenu.setPlayerName(playerName);
					GameLogic.gameState = Constants.NO_TURN;
					rightMenu.updateState();
					break;
					
				case CHAT:
					rightMenu.addStringToChat(infoList.get(0)+": "+infoList.get(1));
					break;
					
				case GAME_LOG:
					rightMenu.addMessageToLog(infoList.get(0));
					break;
					
				case MEETING:
					
					List<String> playerNames = new ArrayList<String>();
					for(int i = 1;i<infoList.size();i+=2)
						playerNames.add(infoList.get(i));
					meetingPanel.setValues(playerNames);
					meetingPanel.askMode();
					meetingPanel.setVisible(true);
					
					break;
					
				case REVELATION:
					
					revelationPanel.setVisible(true);
					
					break;
					
				case ASK_PLAYER_FOR_QUESTIONS: {
					
					String playerAsking = infoList.get(0);
					meetingPanel.setVisible(true);
					meetingPanel.answerMode(playerAsking);
					
				}
				break;
				
				case NEGATIVE_ANSWER_FROM_PLAYER: {
					
					String name = infoList.get(0);
					meetingPanel.negativeAnswer(name);
					
				}
				break;
				
				case AFIRMATIVE_ANSWER_FROM_PLAYER: {
					String name = infoList.get(0);
					meetingPanel.questionsMode(name);
				}
				break;
				
				case QUESTIONS: {
					
					int pos = infoList.indexOf("?");
					int pos2 = infoList.lastIndexOf("?");
					
					List<String> questions= new ArrayList<String>(infoList.subList(0, pos));
					List<String> monkNames = new ArrayList<String>(infoList.subList(pos+1, pos2));
					
					meetingPanel = new MeetingPanel(new Rectangle(350,200,400,400),questions,monkNames,meetingFrameImage,buttonRevelationImageIcon);
					revelationPanel = new revelationPanel(new Rectangle(350,200,400,400), questions, monkNames,revelationFrameImage,buttonRevelationImageIcon);
					playCardPanel = new PlayCardFrame(new Rectangle(getLocation().x+180,getLocation().y+7,620,620), questions, monkImages,infoList.subList(pos2+1, infoList.size()),playerName);
				}
				break;
				
				case FINAL_ANSWER_FROM_QUESTION:
					 JOptionPane.showMessageDialog(meetingPanel,infoList.get(0));
					 meetingPanel.uncheckAll();
					 meetingPanel.setVisible(false);
					break;
				
				case SECOND_QUESTION_ROW:
					meetingPanel.setPlayerAnswering(infoList.get(0));
					meetingPanel.questionsMode(infoList.get(0));
					meetingPanel.setVisible(true);
					break;
				
				case NEW_PLAYER:
					board.addPlayer(Integer.parseInt(infoList.get(0)));
					break;

				case SUSPECTS:
					for(int i=0;i<infoList.size();i++) {
						if(infoList.get(i).equals("1"))
							GameLogic.suspects[i] = true;
					}
					suspectsPanel.getPanel().updateSuspectSheet();
					break;


				case GIVE_ME_PLAYER_INFO:
				{
					inputFrame.setValues(infoList);
					inputFrame.setVisible(true);
				}
				break;

				case NEW_MOVE: {
					int square = Integer.parseInt(infoList.get(0));
					int player = Integer.parseInt(infoList.get(1));
					board.movePlayer(square,player);
					if(playerId==player) {
						GameLogic.gameState &= ~Constants.MOVEMENT;
						rightMenu.updateState();
						rightMenu.updatePlayerUbicationName(infoList.get(2));
					}
				}
				break;
				
				case REJECTED:
					break;
					
				case TAKE_MONK_CARDS:{
					
					for(int i=0;i<infoList.size();i++) {
						GameLogic.monkCards[i] = false;
						if(infoList.get(i).equals("1"))
							GameLogic.monkCards[i] = true;
					}
					cardsPanel.repaint();

				}
				break;
				
				case MESSAGE_FOR_PLAYER:{
					
					JOptionPane.showMessageDialog(this,infoList.get(0));
					
				}
				break;
				
				case MESSAGE_FOR_ALL_PLAYERS:{
					
					JOptionPane.showMessageDialog(this,infoList.get(0));
					
				}
				break;
				
				case IMAGE_MESSAGE:{
					
					int cardType = Integer.parseInt(infoList.get(0));
					int cardNumber = Integer.parseInt(infoList.get(1));
					String cardMessage =infoList.get(2);
					String cardName = infoList.get(3);
					String cardText = infoList.get(4);
					boolean special = Boolean.parseBoolean(infoList.get(5));
					if(cardType == Constants.MONK_CARD_TYPE || cardType == Constants.MISA_CARD_TYPE)
						imageMessage.showMessage(cardType,cardNumber,cardMessage,null,null);
					else if(cardType== Constants.PLAY_CARD_TYPE ) {
						imageMessage.showMessage(cardType,cardNumber,cardMessage,cardName,cardText);
						if(cardNumber == 0) {  // LibraryCard
							playCardPanel.playCard(cardName);
						}
						if(cardNumber == 1 && special) {  // CriptaCard
							rightMenu.addCriptaCard();
						}
						if(cardNumber == 3 || cardNumber == 4 || cardNumber == 5) {  //ScriptoriumCard
							if(special) {
								//guardar carta de scriptorium
							}
							else {
								//jugar carta de scriptorim
								playCardPanel.playCard(cardName);
							}
						}
						
					}
				}
				break;
				
				case SHOW_MONKS_IN_PLAY_CARD_FRAME:
					playCardPanel.showThisCards(infoList);
					break;
				
				case YOUR_TURN:
					GameLogic.gameState |=  Constants.MYTURN | Constants.MOVEMENT;
					GameLogic.gameState &= ~Constants.NO_TURN;
					rightMenu.updateState();
					break;
					
				case TURN_INFO:
					rightMenu.updateGameInfo(infoList);
					break;
				
				default:
					break;
				}
			}
		}
	}

	

	@Override
	public void networkDisconnected() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void networkMessageReceived(Object message) {
		synchronized(messageList) 
		{
			messageList.add((ServerMessage)message);
		}
	}


	@Override
	public void actionPerformed(ActionEvent event) {
		
		JComponent component = (JComponent) event.getSource();
		String componentName = component.getName();
		
		switch(componentName) {
		
		case "Cartas":{
			cardsPanel.setVisible(!cardsPanel.isVisible());
		}
		break;
		
		case "ENVIAR":{
			System.out.println(inputFrame.getValues());
			gameController.takePlayerInfo(inputFrame.getValues());
			inputFrame.setVisible(false);
		}
		break;
		
		case "Sospechosos" :{
			suspectsPanel.setVisible(!suspectsPanel.isVisible());
		}
		break;
		
		case "finTurno" :{
			if((GameLogic.gameState & Constants.MOVEMENT) == 0) {
				GameLogic.gameState &= ~Constants.MYTURN; 
				GameLogic.gameState |= Constants.NO_TURN;
				rightMenu.updateState();
				gameController.endTurn();
			}
		}
		break;
		
		case "chat" : {
			JTextField chatInput = (JTextField) event.getSource();
			String str = chatInput.getText();
			rightMenu.addStringToChat("YO: "+str);
			chatInput.setText("");
			gameController.sendChatMessage(str);
		}
		break;
		
		case "PREGUNTAR": {
			String playerName = meetingPanel.getPlayerToAsk();
			gameController.askPlayerForQuestionMeeting(playerName);
			//meetingPanel.setVisible(false);
		}
		break;
		
		case "ENVIAR VOTO": {
			
			String silenceVote = meetingPanel.getSilenceVoteAnswer();
			if(silenceVote.equalsIgnoreCase("SI")) meetingPanel.setVisible(false);
			gameController.answerPlayerForQuestionMeeting(silenceVote);
			
		}
		break;
		
		case "ENVIAR PREGUNTA": {
			List<String> list = new ArrayList<String>();
			if(meetingPanel.getQuestionValue(list)) {
				gameController.sendQuestion(list);
			}
			else JOptionPane.showMessageDialog(meetingPanel, " formula bien tu pregunta", "PREGUNTA MAL CONSTRUIDA", JOptionPane.DEFAULT_OPTION);
			
		}
		break;
		
		case "sendRevelation":
			List<String> list = revelationPanel.getRevelation();
			System.out.println(list);
			gameController.sendRevelation(list);
			revelationPanel.setVisible(false);
			break;
		
		case "playCardButton":
			String cardName = playCardPanel.getCardName();
			String option = null;
			String player1 = null;
			String player2 = null;
			
			if(cardName.equalsIgnoreCase("demonologia")) {
				option = playCardPanel.getSelectedFeature();
			}
			else if(cardName.equalsIgnoreCase("Texto criptografico")) {
				option = playCardPanel.getSelectedDestiny();
				playCardPanel.setVisible(false);
			}
			else if(cardName.equalsIgnoreCase("Tratado astrologico arabe")) {
				player1 = playCardPanel.getSelectedPlayer1();
				player2 = playCardPanel.getSelectedPlayer2();
			}
			
			playCardPanel.disableSendButton();
			gameController.playCard(cardName,option,player1,player2);
			
			break;
		}
		
	}

	@Override
	public void mouseClicked(MouseEvent arg0) {
		
		JLabel component = (JLabel) arg0.getSource();
		String componentName = component.getName();
		switch(componentName.toLowerCase()) {
		case "cripta": {
			if((GameLogic.gameState & Constants.MOVEMENT)==0 && (GameLogic.gameState & Constants.MYTURN)>0) {
				rightMenu.removeCriptaCard(component);
				gameController.playCard(componentName,null,null,null);
			}
		}
		}
		
	}

	@Override
	public void mouseEntered(MouseEvent arg0) {
		JLabel component = (JLabel) arg0.getSource();
		component.setBorder(Constants.outsideBorder);
		
	}

	@Override
	public void mouseExited(MouseEvent arg0) {
		JLabel component = (JLabel) arg0.getSource();
		component.setBorder(null);
		
	}

	@Override
	public void mousePressed(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mouseReleased(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
	}

}
